import { Injectable, NestMiddleware, Logger } from '@nestjs/common'
import { Request, Response, NextFunction } from 'express'
import morgan from 'morgan'
import helmet from 'helmet'
import compression from 'compression'
import rateLimit from 'express-rate-limit'
import slowDown from 'express-slow-down'

/**
 * 请求日志中间件
 * 记录所有HTTP请求的详细信息
 */
@Injectable()
export class RequestLoggerMiddleware implements NestMiddleware {
  private readonly logger = new Logger('HTTP')

  use(req: Request, res: Response, next: NextFunction) {
    const { method, originalUrl, ip } = req
    const userAgent = req.get('User-Agent') || ''
    const startTime = Date.now()

    // 记录请求开始
    this.logger.log(`${method} ${originalUrl} - ${ip} - ${userAgent}`, 'Request Start')

    // 监听响应结束
    res.on('finish', () => {
      const { statusCode } = res
      const contentLength = res.get('content-length')
      const responseTime = Date.now() - startTime

      const logMessage = `${method} ${originalUrl} - ${statusCode} - ${responseTime}ms - ${contentLength || 0}bytes - ${ip}`

      if (statusCode >= 400) {
        this.logger.error(logMessage, 'Request Error')
      } else {
        this.logger.log(logMessage, 'Request Complete')
      }
    })

    next()
  }
}

/**
 * 安全头中间件
 * 添加各种安全相关的HTTP头
 */
@Injectable()
export class SecurityHeadersMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: NextFunction) {
    // 设置安全头
    res.setHeader('X-Content-Type-Options', 'nosniff')
    res.setHeader('X-Frame-Options', 'DENY')
    res.setHeader('X-XSS-Protection', '1; mode=block')
    res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin')
    res.setHeader('Permissions-Policy', 'geolocation=(), microphone=(), camera=()')

    // 移除敏感头信息
    res.removeHeader('X-Powered-By')
    res.removeHeader('Server')

    next()
  }
}

/**
 * CORS中间件
 * 处理跨域请求
 */
@Injectable()
export class CorsMiddleware implements NestMiddleware {
  private readonly allowedOrigins = [
    'http://localhost:3000',
    'http://localhost:3001',
    'https://yourdomain.com',
    process.env.FRONTEND_URL
  ].filter(Boolean)

  use(req: Request, res: Response, next: NextFunction) {
    const origin = req.headers.origin

    // 检查来源是否被允许
    if (this.allowedOrigins.includes(origin) || process.env.NODE_ENV === 'development') {
      res.setHeader('Access-Control-Allow-Origin', origin || '*')
    }

    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS')
    res.setHeader(
      'Access-Control-Allow-Headers',
      'Origin, X-Requested-With, Content-Type, Accept, Authorization, Cache-Control'
    )
    res.setHeader('Access-Control-Allow-Credentials', 'true')
    res.setHeader('Access-Control-Max-Age', '86400') // 24小时

    // 处理预检请求
    if (req.method === 'OPTIONS') {
      res.status(200).end()
      return
    }

    next()
  }
}

/**
 * 请求ID中间件
 * 为每个请求生成唯一ID
 */
@Injectable()
export class RequestIdMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: NextFunction) {
    const requestId = this.generateRequestId()

    // 添加到请求对象
    ;(req as any).requestId = requestId

    // 添加到响应头
    res.setHeader('X-Request-ID', requestId)

    next()
  }

  private generateRequestId(): string {
    return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
  }
}

/**
 * 响应时间中间件
 * 计算并添加响应时间头
 */
@Injectable()
export class ResponseTimeMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: NextFunction) {
    const startTime = process.hrtime.bigint()

    res.on('finish', () => {
      const endTime = process.hrtime.bigint()
      const responseTime = Number(endTime - startTime) / 1000000 // 转换为毫秒

      // 不在finish事件中设置头部，因为响应已经发送
      // res.setHeader('X-Response-Time', `${responseTime.toFixed(2)}ms`)
    })

    next()
  }
}

/**
 * 用户代理解析中间件
 * 解析用户代理信息
 */
@Injectable()
export class UserAgentMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: NextFunction) {
    const userAgent = req.headers['user-agent'] || ''

    // 简单的用户代理解析
    const userAgentInfo = {
      raw: userAgent,
      browser: this.getBrowser(userAgent),
      os: this.getOS(userAgent),
      device: this.getDevice(userAgent),
      isBot: this.isBot(userAgent),
      isMobile: this.isMobile(userAgent)
    }

    ;(req as any).userAgent = userAgentInfo

    next()
  }

  private getBrowser(userAgent: string): string {
    if (userAgent.includes('Chrome')) return 'Chrome'
    if (userAgent.includes('Firefox')) return 'Firefox'
    if (userAgent.includes('Safari')) return 'Safari'
    if (userAgent.includes('Edge')) return 'Edge'
    if (userAgent.includes('Opera')) return 'Opera'
    return 'Unknown'
  }

  private getOS(userAgent: string): string {
    if (userAgent.includes('Windows')) return 'Windows'
    if (userAgent.includes('Mac OS')) return 'macOS'
    if (userAgent.includes('Linux')) return 'Linux'
    if (userAgent.includes('Android')) return 'Android'
    if (userAgent.includes('iOS')) return 'iOS'
    return 'Unknown'
  }

  private getDevice(userAgent: string): string {
    if (userAgent.includes('Mobile')) return 'Mobile'
    if (userAgent.includes('Tablet')) return 'Tablet'
    return 'Desktop'
  }

  private isBot(userAgent: string): boolean {
    const botPatterns = ['bot', 'crawler', 'spider', 'scraper', 'Googlebot', 'Bingbot', 'Slurp', 'DuckDuckBot']
    return botPatterns.some(pattern => userAgent.toLowerCase().includes(pattern.toLowerCase()))
  }

  private isMobile(userAgent: string): boolean {
    return /Mobile|Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent)
  }
}

/**
 * IP地址中间件
 * 获取真实IP地址
 */
@Injectable()
export class RealIpMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: NextFunction) {
    // 获取真实IP地址（考虑代理和负载均衡器）
    const realIp =
      req.headers['x-forwarded-for'] ||
      req.headers['x-real-ip'] ||
      req.headers['x-client-ip'] ||
      req.connection.remoteAddress ||
      req.socket.remoteAddress ||
      (req.connection as any)?.socket?.remoteAddress ||
      req.ip

    // 处理多个IP的情况（x-forwarded-for可能包含多个IP）
    const clientIp = Array.isArray(realIp)
      ? realIp[0]
      : typeof realIp === 'string'
        ? realIp.split(',')[0].trim()
        : realIp

    ;(req as any).realIp = clientIp

    next()
  }
}

/**
 * 内容类型验证中间件
 * 验证请求的内容类型
 */
@Injectable()
export class ContentTypeMiddleware implements NestMiddleware {
  private readonly allowedContentTypes = [
    'application/json',
    'application/x-www-form-urlencoded',
    'multipart/form-data',
    'text/plain'
  ]

  use(req: Request, res: Response, next: NextFunction) {
    // 只对有body的请求进行验证
    if (['POST', 'PUT', 'PATCH'].includes(req.method)) {
      const contentType = req.headers['content-type']

      if (contentType) {
        const baseContentType = contentType.split(';')[0].trim()

        if (!this.allowedContentTypes.includes(baseContentType)) {
          return res.status(415).json({
            code: 415,
            message: '不支持的内容类型',
            error: 'Unsupported Media Type',
            allowedTypes: this.allowedContentTypes
          })
        }
      }
    }

    next()
  }
}

/**
 * 请求大小限制中间件
 * 限制请求体大小
 */
@Injectable()
export class RequestSizeMiddleware implements NestMiddleware {
  private readonly maxSize = 50 * 1024 * 1024 // 50MB

  use(req: Request, res: Response, next: NextFunction) {
    const contentLength = parseInt(req.headers['content-length'] || '0', 10)

    if (contentLength > this.maxSize) {
      return res.status(413).json({
        code: 413,
        message: '请求体过大',
        error: 'Payload Too Large',
        maxSize: this.maxSize,
        receivedSize: contentLength
      })
    }

    next()
  }
}

/**
 * 健康检查中间件
 * 处理健康检查请求
 */
@Injectable()
export class HealthCheckMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: NextFunction) {
    if (req.path === '/health' || req.path === '/ping') {
      return res.status(200).json({
        status: 'ok',
        timestamp: new Date().toISOString(),
        uptime: process.uptime(),
        memory: process.memoryUsage(),
        version: process.env.npm_package_version || '1.0.0'
      })
    }

    next()
  }
}

/**
 * 维护模式中间件
 * 在维护模式下阻止请求
 */
@Injectable()
export class MaintenanceMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: NextFunction) {
    const isMaintenanceMode = process.env.MAINTENANCE_MODE === 'true'
    const isHealthCheck = req.path === '/health' || req.path === '/ping'
    const isAdminPath = req.path.startsWith('/admin')

    if (isMaintenanceMode && !isHealthCheck && !isAdminPath) {
      return res.status(503).json({
        code: 503,
        message: '系统正在维护中，请稍后再试',
        error: 'Service Unavailable',
        maintenanceMode: true,
        estimatedTime: process.env.MAINTENANCE_ESTIMATED_TIME || '未知'
      })
    }

    next()
  }
}
